home *** CD-ROM | disk | FTP | other *** search
/ ASP Advantage 1994 2nd Q2 / The Association of Shareware Professionals - The Official ASP Advantage (2nd Quarter)(1994).bin / files / progming / bt / bt2.com (.txt) < prev    next >
Encoding:
Asc2Com (MorganSoft)  |  1993-02-12  |  62.8 KB  |  1,248 lines

  1.  
  2.                 B A S I C   T R A I N I N G        
  3.                         Part Two                   
  4.                    by Steve Estvanik               
  5.  
  6. Part 5. GOSUBS and FUNCTIONS
  7. This time we'll be examining GOSUB's and FUNCTIONS.  Up to now, when we've 
  8. wanted to repeat a section of code, we've had 2 choices.  We could just copy 
  9. the code over, or we could set up a loop.  Sometimes that still leaves us 
  10. with a messy solution.  
  11.  
  12. WHY GOSUBS? 
  13. In the previous chapter, one of the exercises involved writing a short 
  14. program that took as input a pair of numbers -- month and day, then 
  15. calculated the number of days elapsed since the start of the year and the 
  16. number of days till the end of the year.  
  17.  
  18. But what if we want to input 2 sets of numbers?  One way would be to repeat 
  19. the code.  Another would be by using a GOSUB.  This is a special command 
  20. that tells the program to jump to a particular line.  It differs from a GOTO 
  21. in that when the command RETURN is found, the program jumps back to the 
  22. statement that called it.  This lets a whole section of code be used in 
  23. several places.  Thus 
  24.  
  25.    10 X = 1                           
  26.    20 GOSUB 100                       
  27.    30 X = 2                           
  28.    40 GOSUB 100                       
  29.    50 X = 3                           
  30.    60 GOSUB 100                       
  31.    70 END                             
  32.    100 PRINT "X squared is";X*X       
  33.    110 RETURN                         
  34.  
  35. This will produce 3 lines showing the squares of 1, 2 and 3.  Note the use 
  36. of the END statement.  Take it out and see what happens.  
  37.  
  38. We can turn the elapsed days calculation into a GOSUB as follows:
  39.  
  40.    10 'julian.bas                                                 
  41.    20 DIM DAYS(12)                                                
  42.    30 DATA 31,28,31, 30,31,30, 31,31,30, 31,30,31                 
  43.    40 FOR I = 1 TO 12 : READ DAYS(I) : NEXT                       
  44.    50 INPUT "Start month";M                                       
  45.    60 INPUT "Start day";D                                         
  46.    70 GOSUB 200                                                   
  47.    80 E1 = ELAPSED                                                
  48.    90 INPUT "End month";M                                         
  49.    100 INPUT "End day";D                                          
  50.    110 GOSUB 200                                                  
  51.    120 DATE.DIF = ELAPSED - E1                                    
  52.    130 PRINT                                                      
  53.    140 PRINT "difference =";DATE.DIF                              
  54.    150 END                                                        
  55.    200 '===================== calc elapsed time in days           
  56.    210 ELAPSED = D                                                
  57.    220 FOR I = 1 TO M - 1                                         
  58.    230 ELAPSED = ELAPSED + DAYS(I)                                
  59.    240 NEXT                                                       
  60.    250 PRINT ELAPSED;"days elapsed. ";365-ELAPSED; "days to go"   
  61.    260 RETURN                                                     
  62.                                                                    
  63. Here we ask for 2 sets of numbers and then calculate the difference 
  64. between them.  When working with dates for comparison you'll usually want 
  65. to deal with the number of days past the beginning of the year, so this 
  66. conversion routine is quite handy.  This notation for dates is called 
  67. Julian (as in Caesar).  
  68.  
  69.  
  70. WE INTERRUPT THIS PROGRAM FOR A POLITICAL ANNOUNCEMENT...
  71. ----------------------------------------------------------
  72. Basic is often criticized for its lack of structure and difficulty in 
  73. reading and maintainence.  This is more of a programmer's problem though, 
  74. not the language's.  You can write structured programs in Basic just as 
  75. you can write spaghetti code in Pascal or unmaintainable trash in C.  
  76. Structured methods will produce good code in any of the languages.  If you 
  77. follow these guidelines you'll be able to keep your programs readable and 
  78. easy to maintain. 
  79.  
  80. ** The main portion of the program should start at the top and proceed to 
  81. the bottom.  This means using FOR-NEXT and WHILE loops rather than GOTO's.  
  82. (In older books or articles you may see the suggestion to jump to the end 
  83. of the program for initializing or other reasons.  This made a small 
  84. amount of sense in the old days, but modern Basic interpreters are much 
  85. more efficient and you won't notice any difference.  What you will get is 
  86. a program that's harder to work on.) 
  87.  
  88. ** Whenever possible, use GOSUB's and, once we've defined them, function 
  89. calls to recycle repetive sections of programs.  (Once a GOSUB is working 
  90. you'll often be able to use them in other programs.  Functions are even 
  91. more transportable.)  With a compiler, we'll use subroutines rather than 
  92. GOSUB's for even more modularity.
  93.  
  94. ** Start each GOSUB with a comment line.  This should be the ONLY entry to 
  95. a GOSUB.  It's legal to enter a GOSUB at any point, but it's just asking 
  96. for trouble.  There are a very few instances where it's justified, but I'd 
  97. put it at less than 1%.  Using the comment line helps to delineate GOSUB's 
  98. in the program.  
  99.  
  100. ** Similarly, the last statement in any GOSUB should be the only RETURN.  
  101. By applying these two rules you abide by one of the central dogmas of 
  102. structured programming -- single input, single output.  This ensures that 
  103. every time the subroutine is used it's used the same.  Thus you won't get 
  104. unpredictable results.  Sometimes you'll have gosubs that finish in the 
  105. middle of a section.  Rather than succumb to the temptation to RETURN from 
  106. that point, use a GOTO to jump down to the single RETURN at the bottom.  
  107. This is an insignificant increase in the amount of code, but results in an 
  108. immense increase in readability and ease of maintainence.  It also makes 
  109. it easier to trace and isolate problems.  If you know there's only one 
  110. entry and one exit, you can concentrate on the routine that's causing the 
  111. problem.  You won't have to worry what conditions are where the gosub is 
  112. called.  If there were multiple entries or exits this would be an 
  113. additional problem.
  114.  
  115.                  GOSUB 100                                   
  116.                  ....                                        
  117.                  END                                         
  118.                                                              
  119.          100     ' ----------- subroutine to do stuff...     
  120.                  { compute stuffs }                          
  121.                  ' are we done?                              
  122.                  IF { final condition achieved } THEN 200    
  123.                  { compute more stuffs }                     
  124.          200     RETURN                                      
  125.  
  126. Stringing these ideas together we can draw a prototype program:
  127.  
  128.          ' main program                                      
  129.            GOSUB 100     ' init stuff                        
  130.                                                              
  131.          ' process stuff                                     
  132.            FOR X = 1 to whatever                             
  133.            GOSUB 200     ' first part of processing          
  134.            GOSUB 300                                         
  135.            NEXT                                              
  136.                                                              
  137.            GOSUB 400     ' final stuff                       
  138.            END                                               
  139.  
  140.       100  '=============== init                             
  141.                                                              
  142.            { .... do processing here }                       
  143.                                                              
  144.            RETURN                                            
  145.      
  146.       200  '=============== first processing                 
  147.                                                              
  148.            { .... do processing here }                       
  149.                                                              
  150.            RETURN                                            
  151.      
  152.       300  '=============== second processing                
  153.                                                              
  154.            { .... do processing here }                       
  155.                                                              
  156.            RETURN                                            
  157.      
  158.       400  '=============== final stuff                      
  159.                                                              
  160.            { .... do processing here }                       
  161.                                                              
  162.            RETURN                                            
  163.  
  164. This is a common way to design a relatively straightforward program.  It's 
  165. much to be preferred to flowcharts.  Here we've outline the structure of 
  166. our entire program without getting bogged down in petty details.  Another 
  167. good feature of this design is that we can prototype.  We could write the 
  168. initializing section and the final processing section without worrying for 
  169. the moment about the 2 middle sections.  We could just put some print 
  170. statements in there to alert us to the fact they need to come later.  This 
  171. method, called Top-Down Design starts with the most important elements of 
  172. the program, the overall structure and works in ever more detail.  In this 
  173. way, the interactions among the program parts is being tested from the 
  174. start.  Try this method with simple programs and you'll find that soon you 
  175. can tackle more complicated projects.  If you're interested in more on 
  176. structured programming, look for books by Constantine or Yourdon.  Most of 
  177. the ideas in these books can be applied to any language.
  178.  
  179.  
  180.  
  181. BACK TO OUR SCHEDULED PROGRAMMING....
  182.  
  183. RENUMBERING (RENUM)
  184.  
  185. If you're using a compiler, you never need to worry about renumbering.  This 
  186. feature alone might be enough to convince you to acquire a compiler.
  187.                                      
  188. RENUM is a command in the Basic interpreter that lets you renumber your 
  189. program.  It's especially useful since it takes care to maintain any 
  190. references you've set up.  All GOTO, RESTORE, IF-THEN and GOSUB relations 
  191. will be the same after the RENUM as they were before.  The numbers may be 
  192. different.  This is the preferred way of changing numbers.  You can do it by 
  193. hand, but if you miss one, it'll be hard to find.  The simplest form of 
  194. RENUM is just 
  195.  
  196.          RENUM                      
  197.  
  198. This renumbers the entire file, using 10 as an increment.  If you have a 
  199. large file and want to reorder just part you can use
  200.  
  201.          RENUM [newnum], [oldnum]   
  202.  
  203. This will start at line [oldnum] and change it to [newnum] and continue 
  204. renumbering from there.  Try this on a practise file until you feel 
  205. comfortable with the power of this command.  
  206.  
  207. There are 2 philosophies about renumbering.  Some people only use the RENUM 
  208. from the start.  Here their GOSUB's will often have changed numbers.  As 
  209. long as you keep current listings, there's no problem.  Others design a 
  210. program with large separations between gosubs.  Thus you might define them 
  211. as 1000, 2000, 3000, ..., and interpolate later as necessary.  This method 
  212. keeps the subroutines in the same place, but is more tedious to renumber.  
  213. You'd need to issue several commands: 
  214.  
  215.          RENUM 1000,1000                         
  216.          then list to find what used to be 2000  
  217.          RENUM 2000,[new 2000 place]             
  218.          then list to find what used to be 3000  
  219.          RENUM 3000,[new 3000 place], etc        
  220.  
  221. Try this with a file with several GOSUB's.  The first method is certainly 
  222. the easiest, and if you're careful to follow the guidelines above your 
  223. program will still be readable. 
  224.  
  225.  
  226. Exercise
  227. A. Design a program that will take 2 dates, prompting for year, month and 
  228. day.  Then calculate the number of days that separate these two dates. 
  229.  
  230. Hint: in our first treatment we ignored leap years.  But when you know the 
  231. year, and are looking over several years you don't have that luxury.  You'll 
  232. need to include a check for leap year in the new elapsed days gosub. 
  233.  
  234.  
  235. FUNCTIONS
  236.  
  237. Functions are similar to gosubs in that they provide a means of using the 
  238. same code in multiple ways and places.  The difference is that functions are 
  239. defined at the start of a program, and, in interpreted Basic, are limited to 
  240. single lines.  The other difference is that there can only be one value 
  241. returned from a function.  The format for defining and using a function is: 
  242.  
  243.        DEF FNstuff(x) = { whatever the functions going to do }  
  244.        ......                                                   
  245.        Y = fnstuff(x) + 10                                      
  246.        .....                                                    
  247.        if fnstuff(x) then print "text 1" else print "text 2"    
  248.  
  249. Note that a function can be used anywhere a variable might be on the right 
  250. side of an assignment statement or in a conditional.  You can't use a 
  251. function on the left hand side though. 
  252.  
  253. Actually we've already used several functions.  RND is a function, so is 
  254. CHR$() that we've used to print ascii characters for the boxes.  These are 
  255. system functions since they come as part of the language.  Other useful 
  256. system functions include STRING$() and SPACE$().  Here's some examples: 
  257.  
  258.     10 for i = 1 to 10                                        
  259.     20 print SPACE$(i);i                                      
  260.     30 next                                                   
  261.     40 for i = 0 to 255                                       
  262.     50 if i<10 and i>12 then print string$((i mod 50) + 1, i) 
  263.     60 next                                                   
  264.  
  265.  
  266. Short exercises
  267. Why do we use (i mod 50) + 1 instead of just i?  why do we need the +1?  Why 
  268. don't we print characters 10 to 12?  Try taking these out and see why. 
  269.  
  270. Three very useful functions are Left$(), Right$() and Mid$().  These allow 
  271. us to process parts of strings.  Try the following: 
  272.  
  273.     10 x$ = "abcdefghijklmnop"  
  274.     20 print left$(x$, 5)       
  275.     30 print right$(x$, 5)      
  276.     40 print mid$(x$, 5,5)      
  277.  
  278. Left$ and right$ give the left- and right-most characters.  The length to be 
  279. used is given as the second parameter.  Mid$() is more versatile.  MID$(x$, 
  280. x, y) returns y characters, starting at the x'th.  A final function for now 
  281. is LEN().  This returns the length of a string.  Thus if we want to copy all 
  282. but the last 2 characters of a string, we could write 
  283.  
  284.           Y$ = left$( x$, len(x$)-2) 
  285.  
  286. We don't even have to know how long x$ is.  We should check that x$ is at 
  287. least three long, though.
  288.  
  289.  
  290. Exercises 
  291. 1. Write gosub that strips blanks from the end of a string x$.  print the 
  292. original length and the new length of the string. 
  293.  
  294. 2. Write a gosub that strips multiple blanks from a string, reducing them 
  295. to single blanks.  Strip all trailing blanks.
  296.  
  297.  
  298.  
  299. Writing your own functions is straightforward.  All functions must start 
  300. with DEF FN then up to 6 characters to name the function.  
  301.  
  302.      DEF FNMAX( a,b) = abs( a >= b ) * a + abs( b > a ) * b 
  303.  
  304. Here's another twist on using conditionals.  The phrase abs ( a >= b ) 
  305. translates to 0 or 1 depending on the values of a and b.  So, if a is larger 
  306. than or equal to b, we'll return  
  307.  
  308.      (1 * a) + (0 * b)  
  309.  
  310. Similarly,
  311.  
  312.     DEF FNMIN( a,b) = abs( a <= b ) * a + abs( b < a ) * b 
  313.  
  314. Some guidelines in designing functions: if a variable appears in the 
  315. definition itself, then it can be replaced by whatever is used in calling 
  316. it.  Any other variables used in the function take the value of the current 
  317. state of that variable.  Thus 
  318.  
  319.          x = fnmin( x, 100)  
  320.  
  321. will ensure that x is no bigger than 100.  The values X and 100 are sent to 
  322. replace a and b.  If we have the function 
  323.  
  324.          DEF FNMAX2(a) = abs( a >= b ) * a + abs( b > a ) * b  
  325.  
  326. then we'd call it with
  327.  
  328.          x = fnmax2(x)   
  329.  
  330. and the function would use whatever value b is currently set to.  This can 
  331. cause strange happenings in your programs.  It's legal, but not recommended 
  332. as good technique. 
  333.  
  334. We can even combine functions in defining a new function:
  335.  
  336.      DEFMINMAX(min, max, x) = fnmin( fnmax( x, min), max) 
  337.  
  338. Does this make sense to you?  If not, try to work it through using a call 
  339. like 
  340.  
  341.       X = fnminmax(10, 100, X) 
  342.  
  343. This is a useful function that ensures that X is in the range between 10 and 
  344. 100.  The function first takes the maximum of X or min, then takes the 
  345. minimum of x or max.  Use this in programs like the checkbook program where 
  346. you can define the expected maximum and minimum values. 
  347.  
  348. Function writing is some of the most fun in Basic.  You can be quite 
  349. creative.  While normally obscure tricks are frowned upon, in functions, 
  350. they're almost okay, as long as you comment them.  Once they work, you can 
  351. use them in many different places.  Another advantage, is that, with proper 
  352. naming conventions your mainline code will be self-documenting.  Which of 
  353. the following is easier to understand? 
  354.  
  355.           X = abs( a <= b ) * a + abs( b < a ) * b  
  356.  
  357. or
  358.  
  359.           X = fnmin(a,b)                           
  360.  
  361. Do it once.  Comment it.  Then put it away and call it when needed.
  362.  
  363.  
  364. Exercise
  365. Using gosubs or functions, write a routine that accepts a string and returns 
  366. a string with 10 @'s before and behind it (@ is ascii 64).  Put a space 
  367. before and after the name.  Thus if we send the routine x$ = "Steve" we'll 
  368. get back 
  369.  
  370.          "@@@@@@@@@@@@ Steve @@@@@@@@@@@" 
  371.  
  372.  
  373. EXTRA CREDIT
  374. Here's a project that will also give you an idea of the way spreadsheets 
  375. work:
  376.  
  377. This project is more difficult than most we've looked at.  Even if you 
  378. don't do the actual programming, it would be worthwhile to design a 
  379. prototype on paper so that you understand the methods involved.
  380.  
  381. Start with the modified totals program from last time which shows 6 
  382. products over 12 months.
  383.  
  384. 1. Write a 2 functions that take as input the I,J coordinates of the array 
  385. X and return the screen row and column where that element should be 
  386. printed. 
  387.          DEF FNROW(i,j) = ???                  
  388.          DEF FNCOL(i,j) = ???                  
  389.  
  390. Now when we want to update element X(I,J) we can write
  391.  
  392.          ROW = FNROW(I,J)                      
  393.          COL = FNCOL(I,J)                      
  394.          LOCATE ROW, COL                       
  395.  
  396. In fact, we can eliminate the assignments and just use the functions: 
  397.  
  398.          LOCATE FNROW(I,J), FNCOL(I,J)         
  399.  
  400. 2. Move the totals calculations to a GOSUB.
  401.  
  402. 3. Use a gosub to prompt on lines 23 and 24 for the row and col to update.  
  403. Check that the row and columns are valid.  Give an error message if 
  404. they're not.  Don't allow entry of 0's as we're going to calculate them. 
  405.  
  406.  
  407. 4. Once you have the new row and column, prompt and get a new value, then 
  408. recalculate the totals and use the functions to redisplay only the fields 
  409. that have changed. 
  410.  
  411. One approach would be to get the new row and col I,J then store the old 
  412. value of X()
  413.  
  414.          OLDVAL = X(I,J)                       
  415.  
  416. Now recalc the totals:
  417.  
  418.          X(0,J) = X(0,J) - OLDVAL + X(I,J)     
  419.          X(I,0) = X(I,0) - OLDVAL + X(I,J)     
  420.          X(0,0) = X(0,0) - OLDVAL + X(I,J)     
  421.  
  422. Then redisplay these 3 values plus X(I,J)
  423.  
  424.  
  425. In outline form:
  426.  
  427.          { get initial values }                                
  428.          GOSUB 1000              ' calc totals                 
  429.          { display initial values using functions              
  430.            to locate the elements }                            
  431.                                                                
  432.          WHILE {still asking for more changes}                 
  433.            GOSUB 2000              ' get new row, col          
  434.            GOSUB 1000              ' calc totals               
  435.            { use functions to display totals & new value}      
  436.          WEND                                                  
  437.  
  438.      1000 '======= calc totals                                 
  439.           RETURN                                               
  440.                                                                 
  441.      2000 '======= get new row & col                           
  442.           RETURN                                               
  443.  
  444.  
  445.  
  446. Part 5. FILES
  447.  
  448. In previous chapters we learned how to structure programs and reuse sections 
  449. of code with GOSUBs and FUNCTIONs.  At this point, you've learned enough 
  450. about Basic to write useful programs.  However, we still have no way of 
  451. preserving the results of a program.  What if we want to keep results from 
  452. one run to another.  The solution is the use of files.  
  453.  
  454. We've already used files to save our Basic programs.  When you do a normal 
  455. save from within Basic, only the Basic interpreter can use it.  If you want 
  456. to see the program in more readable form, you can save it as an ASCII file 
  457. by modifying the save command: 
  458.  
  459.             SAVE "progname.bas", A   
  460.  
  461. Try this with one of your programs, using a different name so that you have 
  462. the original and the ascii version.  Then exit Basic and use DIR to look at 
  463. the sizes of the programs.  Notice that the ascii cersion takes up more 
  464. room.  Next use the TYPE command to examine the files: 
  465.  
  466.             TYPE "origname.bas"      
  467.             TYPE "progname.bas"      
  468.  
  469. If you have an editor or word processor, you'll find that you can modify the 
  470. ascii version but not the original.  (If you use an editor, though, you'll 
  471. be responsible for putting in your own line numbers.) 
  472.  
  473. Other common uses of files are to hold data that must remain when the 
  474. computer is turned off, or to handle large quantities of data.  Basic 
  475. provides 2 ways to handle files -- sequential and random access.  
  476.  
  477.  
  478. Sequential versus Random
  479.  
  480. Some of this chapter may seem more techincal than previous installments.  
  481. Don't worry about the details.  The important thing is to understand the 
  482. distinctions between the 2 types of files and when each is appropriate. 
  483.  
  484. All files contain records.  Records are the repeating elements within a 
  485. file.  They in turn are usually broken down into fields.  For example, a 
  486. file record for a mailing list program might have fields with the name, 
  487. address and phone number of each person.  Sequential and random files handle 
  488. records and fields quite differently.  Each has definite advantages and 
  489. drawbacks.  
  490.  
  491. Sequential files read or write from the start of the file and proceed in an 
  492. orderly fashion to the end of the file.  Think of them as a cassette tapes.  
  493. In order to find out what's in the tenth record, we need to read the 
  494. preceding 9 records.  (We may not do anything with the information we read, 
  495. but we have to read it).  Random files give you immediate access to any 
  496. record in the file.  A jukebox with its dozens of records is a good example.  
  497. When you request a record, the mechanical arm goes directly to the record 
  498. you requested and plays it.  In computer programs, sequential files must 
  499. always be accessed from the beginning, while random files can select any 
  500. record at any time. 
  501.  
  502.  
  503.  
  504. What's in a file?
  505.  
  506. Consider a file as a group of bytes.  Any additional structure is our 
  507. logical description for convenience and understanding.  We'll set up a 
  508. simple data record and see how the two types of files deal with it.  Our 
  509. data consists of the following fields: 
  510.  
  511.             name    
  512.             city    
  513.             age     
  514.             phone   
  515.  
  516. The following program asks for the information to make 3 records, then 
  517. stores them to a file.  It then reads that file and displays the results on 
  518. the screen.  Ignore the actual commands for the moment, and concentrate on 
  519. what the program is trying to do.  First we'll do it sequentially.  (see the 
  520. program SEQFILE.BAS) 
  521.                                                 
  522. We read the name, city, age and phone number (lines 30-80), then write them 
  523. to the file (lines 90-120).  When we're done, the file physically looks like 
  524. this: 
  525.  
  526.          ------------------------------------------------------  
  527.          | .name............/.city......./age/.phone.../.name.|  
  528.          | ...../.city......./age/.phone.../.name....../.city.|  
  529.          | ...../age/.phone...                                |  
  530.          ------------------------------------------------------  
  531.  
  532. However, when we read it back in, it's interpreted this way:
  533.  
  534.               .name............/     
  535.               .city......./          
  536.               age/                   
  537.               .phone.../             
  538.               .name.. ...../         
  539.               .city......./          
  540.               age/                   
  541.               .phone.../             
  542.               .name....../           
  543.               .city....../           
  544.               age/                   
  545.               .phone...                               
  546.  
  547. Note that each record takes up a variable amount of space in the file.  Thus 
  548. we have no way of predicting where a particular record begins.  If we start 
  549. at the beginning and just read one record, field by field that never 
  550. concerns us.  Sequential files are thus most useful when we have either very 
  551. short files, or when we know we'll always want to read the entire file into 
  552. memory.  Their main advantage is that they're easy to program and maintain. 
  553.  
  554. We'll look at the organization of a random file, then return to see how to 
  555. program them.  The following program performs the same tasks as the first, 
  556. but creates a random access file (See RANDFILE.BAS) 
  557.  
  558. Again, we read the name, city, age and phone number, and write them to the 
  559. file.  This time, the file will physically look like this: 
  560.  
  561.       ---------------------------------------------------  
  562.       | name................city..............agphone...|  
  563.       | name................city..............agphone...|  
  564.       | name................city..............agphone...|  
  565.       ---------------------------------------------------  
  566.  
  567. Even though the file is called random, the data appears ordered!  Each 
  568. record consists of 48 bytes or characters.  The information is stored 
  569. exactly the same for each record.  Thus if we want to find the third record, 
  570. we know that it begins on the 97th byte.  There's no need to look at the 
  571. intervening information.  We can point directly to the start of the record 
  572. and read it.  Random access files are a bit more complex than sequential, 
  573. and take more programming effort to maintain, but they are much more 
  574. flexible.  They're best suited to cases where data will be required in no 
  575. particular order.  
  576.  
  577. Random files are also preferred for large files that are frequently updated.  
  578. Consider, if you have 1000 records and change 10 of them, a sequential file 
  579. makes you read all 1000, make the changes, then write all 1000 again.  
  580. That's 2000 disk reads and writes.  With a random file, you only need 10 
  581. reads and 10 writes. 
  582.  
  583.  
  584. USING FILES
  585. Now that we have some idea of why we have two types of files, let's look at 
  586. how to use them: 
  587.  
  588. The programs introduce several new commands and concepts.  The first is the 
  589. control of files.  The OPEN and CLOSE commands tell DOS which areas of the 
  590. disk to manipulate.  You can have several files open at one time.  For 
  591. example, you might have a customer file, an invoice file and a pricing file.  
  592. Basic distinguishes among them by assigning a number to each one.  The # 
  593. sign in front of the file number is optional, but recommended to distinguish 
  594. it as an identifier rather than a numeric value.  OPEN is used by both types 
  595. of files, but has a different syntax for each.  CLOSE is used when you're 
  596. finished with a file.  When you leave a Basic program, all files will be 
  597. automatically closed, but it's good practise to have your program do it. 
  598.  
  599.  
  600. SEQUENTIAL DETAILS
  601.  
  602. Sequential files must be opened for either reading or writing.  In either 
  603. case, an invisible pointer is maintained that indicates where the next 
  604. record is coming from.  The format of the statement is 
  605.  
  606.         OPEN filename FOR [ INPUT / OUTPUT / APPEND ] AS handle  
  607.  
  608. where filename is any explicit filename or variable.  Usually existing files 
  609. are read first, new information added, then the entire file is written out.  
  610. APPEND is a special form of OUTPUT.  Any existing file is kept and new 
  611. information is added to the end of the file.  An example might be a file 
  612. that keeps a list of errors encountered during the program.  There's no need 
  613. to read in previous errors, but you also don't want to destroy them.  So you 
  614. use APPEND to add to the back of the file.  
  615.  
  616. Since the filename can be a variable, you can make your programs more user-
  617. friendly by showing the user what files are available.  For example, if you 
  618. have a series of files that are called MAR.DAT, APR.DAT, etc, you could 
  619. display a list with the FILES command and then prompt for the one the user 
  620. wants.  The FILES command puts a directory on the screen.  You can use 
  621. wildcards to limit the files displayed: 
  622.  
  623.             10 FILES "*.dat"                            
  624.             20 INPUT "Which file to report"; filename$  
  625.             30 OPEN filename$ FOR OUTPUT AS #2          
  626.  
  627. Records are written and recovered with the PRINT #, WRITE #, and INPUT # 
  628. statements.  INPUT # reads the requested variables from the given file.  You 
  629. have to be careful that the variable types match.  Ie, you can't read a 
  630. string into an integer variable.  PRINT # has several problems for 
  631. beginners, mostly related to how it formats the fields before writing.  The 
  632. Basic manual describes the problems and their solutions if you're in a 
  633. masochistic mood.  For our purposes, the WRITE # statement is more useful.  
  634. It encloses each string in quotation marks and separates fields on a line by 
  635. commas.  In this example, we've made it even simpler by writing each field 
  636. separately.  (WRITE places a linefeed at the end of each operation, so when 
  637. you TYPE TEST.DAT each field will be on a separate line.  This uses an extra 
  638. byte per line, but makes data files easier to display and programs easier to 
  639. debug.) 
  640.  
  641.  
  642. RANDOM NOTES
  643.  
  644. Random files, as illustrated in the second program use the same OPEN 
  645. statement for input and output.  After assigning a number, they also require 
  646. a length for each record.  The FIELD statement is also required before a 
  647. random file can be used.  This command defines the length of each field in a 
  648. record.  You should be careful to use different variable names for the field 
  649. elements and for your actual data.  There are some places where Basic lets 
  650. you use the same name, but you're taking an unncessary risk of causing bugs.  
  651. Since the field statement defines the length of each field, you have to do a 
  652. little more planning with random files.  In the sequential file, we never 
  653. had to consider the length of a name, or whether a phone number had an area 
  654. code attached.  Here, we make the conscious decision that names will be only 
  655. 20 characters, and that phone numbers will not have area codes.  A special 
  656. case is the storage of numbers.  All items in random files are stored in a 
  657. special format.  For numbers, this means all integers are stored as 2 bytes.  
  658. Even if the actual number is 4 or 5 digits, it's compressed before storage 
  659. using the functions defined below.  (Thus random files are often much 
  660. smaller than sequential files.) 
  661.  
  662. The next difference is seen in the method used to write a record.  First all 
  663. fields are determined.  Then, each element of the field statement is set up 
  664. using the LSET statement.  For strings, this is just an assignment: 
  665.  
  666.             LSET field.element = string.variable         
  667.  
  668. For integers, we first need to make the number into a string using the 
  669. special function MKI$()
  670.  
  671.             LSET field.element = MKI$( integer.variable) 
  672.  
  673. (Similar MK functions are available for converting single and double 
  674. precision numbers.) 
  675.  
  676. Then we write this record with the statement
  677.  
  678.             PUT #1, rec.number   
  679.  
  680. Note that we don't even mention the fields.  The FIELD statement 
  681. automatically takes current values of n$, c$, a$ and p$ associated with file 
  682. #1 and uses them in GET and PUT statement.  Note also, that if, for the next 
  683. record, we just changed the n$, the previous values of the other elements 
  684. would remain. 
  685.  
  686. To read a record, we need only it's position.  To read the third 
  687. record:
  688.  
  689.             GET #1, 3          
  690.  
  691. Now the element values are in n$, c$, a$ and p$ so we need to translate them 
  692. to variables that can be used in our program (lines 190-220).  The converse 
  693. of MKI$() function is CVI(), or convert integer. 
  694.  
  695.  
  696. That's it!  Now we have 2 methods for saving data and several ways to 
  697. manipulate the files.  
  698.  
  699.  
  700. Questions 
  701. *** Add verification to the programs to ensure that the age is within a 
  702. certain range and that all phone numbers are of the form XXX-XXXX. 
  703.  
  704. For the following, write down what you think will happen before trying it 
  705. with the programs.  
  706.  
  707. *** What happens if you enter unanticipated data to each file?  Eg, 
  708. what occurs if you enter a 3 or 4 digit age?  or a phone number with 
  709. zip code?  
  710.  
  711. *** What happens if the name contains commas or quotation marks?
  712.  
  713. *** What happens if you open and read a random file in a sequential 
  714. manner or vice versa? 
  715.  
  716.  
  717. PROJECTS
  718.  
  719. These projects are a little longer than the average,  but most of them use 
  720. sections we've done previously.  When you finish these you'll have a good 
  721. working understanding of Basic files. 
  722.  
  723. 1. Sequential files
  724. Use the earlier checkbook programs to create a checkbook file.  This 
  725. should use the following records:
  726.  
  727.             check number       
  728.             description        
  729.             amount             
  730.  
  731. At the start of the program, you'll need to read in the starting balance.  
  732. At the end, you'll have the ending balance.  An outline of the program might 
  733. be: 
  734.  
  735.             dim check(200), desc$(200), amount(200)                   
  736.                                                                       
  737.             open "checks.dat" for input as #1                         
  738.             input #1, start.balance                                   
  739.             input #1, n.checks                                        
  740.             for n = 1 to n.checks                                     
  741.             input #1, check(n), desc$(n), amount(n)                   
  742.             next                                                      
  743.             input #1, final.balance                                   
  744.                                                                       
  745.             { prompt for transactions, keep a running total }         
  746.             close 1                                                   
  747.             open "checks.dat" for output as #1                        
  748.             write #1, start.balance                                   
  749.             write #1, n.checks                                        
  750.             for n = 1 to n.checks                                     
  751.             write #1, check(n), desc$(n), amount(n)                   
  752.             next                                                      
  753.             write #1, final.balance                                   
  754.             close                                                     
  755.  
  756. It would also be nice to have a report program.  This would just read the 
  757. file and print a report.  You should have the deposits and debits in two 
  758. different columns. 
  759.             
  760. 2. Random files
  761. Change the earlier name and address example to allow updates and additions.  
  762. In outline form: 
  763.  
  764.             open "test2.dat" as #1 len=48                             
  765.             field 1, .....                                            
  766.                                                                       
  767.             prompt for highest record number                          
  768.             [ normally this would be stored in the file itself,       
  769.               but for simplicity, assume that the user must know. ]   
  770.                                                                       
  771.             prompt "Add or Update or Display?"                        
  772.                                                                       
  773.             If {ADD} then                                             
  774.                 {record number?}                                      
  775.                 {prompt for information}                              
  776.                 {write record}                                        
  777.                                                                       
  778.             If {Update} then                                          
  779.                 {record number?}                                      
  780.                 {read current information}                            
  781.                 {display current information}                         
  782.                 {information to change?}                              
  783.                 {write record}                                        
  784.                                                                       
  785.             If {Display} then                                         
  786.                 {record number?}                                      
  787.                 {read current information}                            
  788.                 {display current information}                         
  789.                                                                        
  790. Note that there are several candidates for GOSUBs or FUNCTIONs here.  What 
  791. happens if you read a record beyond the end of the file?  What if you write 
  792. past the end? 
  793.  
  794. If you don't have the time to do the entire program, implement only one part 
  795. of it.  Put in the prompting for the other sections anyway.  If those 
  796. sections are selected, then print a short message saying that the selection 
  797. chosen isn't available yet.  This is a method that's often used in actual 
  798. software development.  You block out the main segments of the program, then 
  799. use stubs to indicate where later functions will be.  This way a partial 
  800. program can be tested early rather than trying to debug an entire program at 
  801. once. 
  802.  
  803.  
  804. Part 7: Simple Graphics
  805.  
  806. In the next few sections, we'll look at the graphics abilities of the IBM 
  807. PC.  To fully use these chapters, you'll need access to an IBM with a CGA, 
  808. EGA or VGA board and monitor.  These are graphics adapters that allow you to 
  809. go beyond simple text.  
  810.  
  811. WIDTH
  812.  
  813. So far whenever we've written information to our monitor screen, we haven't 
  814. done anything special.  Thus we've accepted Basic default modes of text 
  815. screens with 80 columns.  There are several ways we can change these 
  816. defaults.  We can set the width of a text screen to be either 40 or 80.  In 
  817. 40 column, the letters are larger, so sometimes easier to read.  80 column 
  818. mode is crisper with sharper colors.  Both modes have their applications.  
  819. To change from one mode to another, use the WIDTH command 
  820.  
  821.             WIDTH screen.width    
  822.  
  823. On a monochrome screen, the width command works, but the size of 
  824. characters doesn't change.  All that happens is that display is limited 
  825. to the left hand side of the screen.  
  826.  
  827.  
  828. SCREEN 
  829.  
  830. Let's examine how the IBM screen display is set up.  This is specific to the 
  831. IBM PC environment.  If a machine fails the compatibility test it's often 
  832. related to how its video display is set up.  Any "100% compatible" machine 
  833. must be able to perform all the commands that we'll discuss in these next 
  834. few sections. (You can use the example programs to test their claims when 
  835. shopping!) 
  836.  
  837. The following few paragraphs may tell you more than you want to know about 
  838. the internals of video displays.  You can skim them if you wish, then catch 
  839. up with us below (just press F2) 
  840.  
  841. The first thing we'll need to understand is what an attribute is.  
  842. Attributes describe how a character is displayed on the screen.  We've 
  843. actually been using attributes without worrying about them up to now.  Basic 
  844. lets you do this with the COLOR command.  When you enter, 
  845.  
  846.             COLOR 15,1         
  847.  
  848. you're telling Basic to set the attribute to 31 which is displayed as 
  849. intense white on a dark blue background.  COLOR commands stay in effect 
  850. until the next COLOR command is issued.  But why 31?  The attribute byte, 
  851. like all bytes can take values from 0 to 255.  We can look at it as a series 
  852. of 8 bits, each of which can be 0 or 1.  The positions within the byte are 
  853. interpreted as follows: 
  854.  
  855.                 ┌──┬────────┬──┬────────┐                      
  856.                 │  │        │  │        │                      
  857.                 └──┴──┴──┴──┴──┴──┴──┴──┘                      
  858.                   \  \_____\  \  \______\                      
  859.                    \     \     \     \                         
  860.                     \     \     \     foreground = 000 to 111  
  861.                      \     \     intensity 0 or 1              
  862.                       \     background 000 to 111              
  863.                        blinking 0 or 1                         
  864.  
  865. Looks intimidating, but in practise, it's easy to use.  It's an extremely 
  866. efficient way to code the foreground color, its intensity, the background 
  867. color, and whether or not the character is blinking, all in one number.  The 
  868. foreground color can vary from 0 to 7, in binary terms this means 
  869.  
  870.             000 = 0   black              
  871.             001 = 1   blue               
  872.             010 = 2   green              
  873.             011 = 3   cyan               
  874.             100 = 4   red                
  875.             101 = 5   magenta            
  876.             110 = 6   yellow/brown       
  877.             111 = 7   white              
  878.  
  879. Thus any 3 bits can be used to code for 8 numbers.  Next we code the 
  880. intensity by setting the 4'th or 8's bit on if we want intense color, 
  881. leaving it at 0 otherwise.  So to code for intense white, we'd use 1111.  
  882. The initial 1 says intense, the next 3 give 7, white's code.  Binary 1111 is 
  883. the same as decimal 15, the number we've been using for intense white all 
  884. along.  We can also code 8 possible background colors using another 3 bits.  
  885. Since these start in column 5, this is the same as multiplying them be 2 to 
  886. the 4th power = 16.  (Column 1 is 2 to the 0th = 1.)  That brings our total 
  887. to 7 bits.  We use the last, the 128's column bit to show whether or not to 
  888. blink.   We've wasted nothing and stored 4 pieces of information in one tiny 
  889. byte.  There's no need to remember all the details.  To use attributes you 
  890. need only use the following formula: 
  891.  
  892.         attribute = 16 * background color + foreground color   
  893.         if intense then attribute = attribute + 8              
  894.         if blinking then attribute = attribute + 128           
  895.  
  896. We can make this into a function: 
  897.  
  898.         DEF FNATT(fgd, bgd, intense, blink) =                  
  899.             128 * blink + bgd*16 + intense * 8 + fgd           
  900.  
  901. so if we wanted to calculate the attribute for intense white on blue, 
  902. we'd use:
  903.  
  904.             att = fnatt(7,1,1,0)               
  905.  
  906.  
  907. Okay, the skimmers should have caught up with us by now.... 
  908.  
  909. In order to store information on the screen, we need to know what to put 
  910. there, and how to display it.  The IBM method stores the information as 
  911. repeating pairs of bytes.  Even numbered bytes tell which ascii character, 
  912. odd bytes give their attribute.  
  913.  
  914. If each character needs 2 bytes, then a 25 line screen of width 80 requires 
  915. 4000 bytes.  A 40 column screen needs only 2000.  However, the IBM video 
  916. display has room to store 16K!  Early applications failed to capitalize on 
  917. this extra memory, since the tricks we'll look at now work only with color 
  918. graphics adapters and their successors.  It turns out that we can use that 
  919. extra memory to display multiple screens at once.  We can think of the IBM 
  920. memory as being a chunk of 16K broken down as follows: 
  921.  
  922.             ------------------------------   
  923.             |   80 col    |    40 col    |   
  924.             ------------------------------   
  925.             |0            |0             |   
  926.             |             |----- 2K -----|   
  927.             |             |1             |   
  928.             ----- 4K -----|------4K------|   
  929.             |1            |2             |   
  930.             |             |----- 6K -----|   
  931.             |             |3             |   
  932.             ----- 8K -----|----- 8K------|   
  933.             |2            |4             |   
  934.             |             |---- 10K -----|   
  935.             |             |5             |   
  936.             ---- 12K -----|---- 12K------|   
  937.             |3            |6             |   
  938.             |             |---- 14K -----|   
  939.             |             |7             |   
  940.             ---- 16K -----|---- 16K------|   
  941.         
  942. Normally, we'd say that Basic limits us to 64K of code and data in our 
  943. programs.  However, the IBM video display can be thought of as an additional 
  944. 16K of memory.  We'll look at some ways that extra memory can be used.  The 
  945. first and simplest way is just to display information.  In the default 
  946. screen of 80 columns and 25 rows, we have 4000 bytes of information.  
  947. Looking at the map, we see that in fact there's room for 4 pages of 
  948. information, numbered 0 to 3.  Similarly, the 40 column width gives us 8 
  949. pages, from 0 to 7.  The SCREEN command lets us switch among these pages.  
  950.  
  951.             SCREEN mode, burst, apage, vpage  
  952.  
  953. For now, the only mode we'll use is 0  which is text mode.  The burst is 0 
  954. for RGB screens, 1 for composite.  (This is an archaic leftover from early 
  955. video monitors.  Set the burst to 1 for any modern system.) The two 
  956. interesting guys are apage and vpage, standing for active page and visual 
  957. page.  These can range from 0 to 3 or 7 depending on width.  The visual page 
  958. is the screen you're currently showing on your monitor.  The active page is 
  959. the page to which your program reads or writes.  Normally these are the 
  960. same, but some interesting effects are possible if you vary them.  Screens 
  961. are easier to show than explain.  (See program SCR.BAS). 
  962.  
  963.  
  964. This program shows how screens work.  First we write a line on each of the 4 
  965. screens, switching both active and visual.  Then we write to each of the 
  966. screens, while keeping 0 as the active screen.  Finally we switch from 
  967. screen to screen without  writing anything more, to prove that in fact we 
  968. have done something.  Why bother?  What happened while the program was 
  969. writing to the other pages?  Did you notice a delay?  What if you had 
  970. several pages of information, such as instructions that you wanted to store 
  971. for easy reference, and didn't want to rewrite each time?  If you stored 
  972. them to an alternate page, you'd only have to write them once, then by just 
  973. shifting screens you could get that information instantly.  
  974.  
  975.  
  976. Exercise
  977. Using the checkbook balancing program, change the program so that any errors 
  978. are displayed on an alternate page.  Write the error first, then shift to 
  979. the page.  Keep track of errors and write each one on a new line.  (Be 
  980. careful that you don't try to write past line 25!)  After each error, shift 
  981. to the page showing accumulated errors, then wait for a keypress before 
  982. coming back to the main program. 
  983.  
  984.             
  985. The commands we'll be learning next are:
  986.  
  987.             CIRCLE     
  988.             LINE       
  989.             PSET       
  990.             PAINT      
  991.  
  992. In addition we'll see new uses for:
  993.  
  994.             COLOR      
  995.             SCREEN     
  996.  
  997. We'll look at 2 programs this time that illustrate these commands:
  998.  
  999.       ** PALETTE.BAS shows the combinations of colors we can achieve
  1000.  
  1001.       ** LINES.BAS  shows some of the straighter applications
  1002.  
  1003. First we'll look at circles and colors:
  1004.  
  1005.     10     'palette.bas                                        
  1006.     15    KEY OFF                                              
  1007.     20      CBK = 1                                            
  1008.     30     PALET = 0                                           
  1009.     40     P = 0                                               
  1010.     50     P2 = 0                                              
  1011.     60     SCREEN 1,P2 : COLOR CBK, PALET : CLS                
  1012.     70     GOSUB 250                                           
  1013.     80     X$=INPUT$(1)                                        
  1014.     90    WHILE X$ <> " "                                      
  1015.     100       IF X$ <> "P" AND X$ <> "p" THEN 160              
  1016.     110            P = P + 1                                   
  1017.     120            IF P > 2 THEN P = 0                         
  1018.     130            PALET = P MOD 2                             
  1019.     140            IF P = 2 THEN P2 = 1 ELSE P2 = 0            
  1020.     150            SCREEN 1, P2                                
  1021.     160     IF X$ <> "B" AND X$ <> "b" THEN 190                
  1022.     170          CBK = CBK + 1                                 
  1023.     180          IF CBK > 31 THEN CBK = 0                      
  1024.     190     COLOR CBK, PALET                                   
  1025.     200     GOSUB 250                                          
  1026.     210     X$ = INPUT$(1)                                     
  1027.     220  WEND                                                  
  1028.     230  SCREEN 0,0 : COLOR 15,1                               
  1029.     240  END                                                   
  1030.     250 ' --------- showit                                     
  1031.     260  FOR I = 1 TO 3                                        
  1032.     270  CIRCLE (50 + I* 50, I*40), 30, I                      
  1033.     280  PAINT  (50 + I* 50, I*40),  I, I                      
  1034.     290  NEXT                                                  
  1035.     300 LOCATE 21,5: PRINT "screen 1,";P2;                     
  1036.     310 PRINT  " COLOR";CBK;",";PALET                          
  1037.     320  LOCATE 22,5: PRINT "Use 'B' to change background";    
  1038.     330  LOCATE 23,5: PRINT "Use 'P' to cycle palettes";       
  1039.     340  LOCATE 24,5: PRINT "Press spacebar when done....";    
  1040.     350  RETURN                                                
  1041.  
  1042. I use a variation of this routine in several of my games.  It gives players 
  1043. the ability to configure the colors to their taste (or lack thereof).  Let's 
  1044. look at how it's done: 
  1045.  
  1046. First, we'll meet the new players:
  1047.  
  1048. SCREEN  -- In earlier chapters we used SCREEN 0 to switch among text 
  1049. screens.  Here, we use SCREEN 1,0 to tell Basic we wish to use graphics.  
  1050. This changes the orientation of the screen from 80 by 25 text characters to 
  1051. 320 by 200 pixels or dots.  This lets us create graphics images, lines and 
  1052. patterns. 
  1053.  
  1054. COLOR  -- This command is similar to that used in text mode.  However, the 
  1055. second argument can only be 0 or 1.  The first argument still sets the 
  1056. background color.  
  1057.  
  1058.             COLOR 2, 0 
  1059.  
  1060. This sets the background to green, and uses the 0 palette.  CGA Graphics 
  1061. mode has two palettes -- 0 uses colors green/red/yellow-brown and 1 uses 
  1062. cyan/magenta/white.  If you issue a palette change command, the screen stays 
  1063. the same and the color switch.   An undocumented palette can be achieved by 
  1064. issuing the SCREEN 1,1 command.  This is illustrated in the program.  This 
  1065. palette contains cyan/red/white and can make your programs more appealing 
  1066. than the universal cyan/magenta of IBM graphics.  
  1067.  
  1068. CIRCLE -- This command, not surprisingly, draws a circle of given color 
  1069. and radius.
  1070.  
  1071.             CIRCLE (X,Y), radius, color  
  1072.  
  1073. Here, the cursor will be at X,Y (in pixels), with 0,0 at the upper left 
  1074. hand corner.  The radius is in pixels, and the color is 0 to 3.  
  1075.  
  1076.  
  1077. PAINT  -- fills an area with a color, starting at the indicated point.  
  1078. For circles or boxes, the center works well, but it's not required.  The 
  1079. paint starts at that point and continues in all directions until a line of 
  1080. the indicated color is reached.  Unfortunately, PAINT has a nasty habit of 
  1081. leaking if you try to PAINT an unclosed object, so use it with care. 
  1082.  
  1083. The next program builds on what we've learned with screen and color and 
  1084. adds straight lines and patterns.  (See program LINES.BAS, included in the 
  1085. shareware package.)
  1086.  
  1087. In addition to the commands we met earlier, this program introduces 2 
  1088. new ones:
  1089.  
  1090. PSET (X,Y), color -- places a dot of color at the indicated pixel.  You 
  1091. can think of this as anchoring the cursor, also, similar to the LOCATE 
  1092. command in text mode. 
  1093.  
  1094. LINE -- This command has two forms, and several options.  It's simplest, 
  1095. but longest form is 
  1096.  
  1097.             LINE (x1,y1) - (x2,y2),color    
  1098.  
  1099. This draws a line from x1,y1 to x2,y2 in this color.  From this point, we 
  1100. could write 
  1101.  
  1102.             LINE (x2,y2) - (x3,y3),color    
  1103.  
  1104. to add a new segment starting at x2,y2, or we could just write
  1105.  
  1106.             LINE - (x3,y3),color               
  1107.  
  1108. which says to draw the line from the last cursor location to x3,y3.  There's 
  1109. a simple way of drawing boxes and optionally filling them.  Just add the 
  1110. commands B or BF to the LINE command: 
  1111.  
  1112.             LINE (x1,y1) - (x2,y2), c, b       
  1113.             LINE (x1,y1) - (x2,y2), c, bf      
  1114.  
  1115. Here the two points represent the upper left and lower right corners of a 
  1116. box.  The 4 lines represented by these corners are drawn automatically. 
  1117.  
  1118. The exercises this time are a little more involved than previously.  This is 
  1119. because Basic graphics commands are fun to play with, AND because there are 
  1120. several points that can best be made after you've had some time to 
  1121. experiment.  Even if you don't do any of the exercises, you might find it 
  1122. interesting to read through this exercise section. 
  1123.  
  1124.  
  1125. Exercises
  1126.  
  1127. A. Create a program that randomly draws boxes and circles on the screen, 
  1128. filling them with color.  Experiment with different colored borders and 
  1129. painting.  Watch what happens when borders overlap. 
  1130.  
  1131. At this point in the series, if you've been doing your homework, you should 
  1132. find the previous exercise straightforward.  The next project should be more 
  1133. challenging! 
  1134.  
  1135. B. This project is quite similar to the simple game proposed last time.  The 
  1136. intent this time is slightly different.  By using the function keys we can 
  1137. create a simple line drawing program.  
  1138.  
  1139. 1. First draw a large box on the screen.  Don't allow the user to cross this 
  1140. boundary.  (Solution hint:  You'll need to calculate the x,y coordinates 
  1141. before you draw them & check them against some boundary conditions.  For 
  1142. example, if you draw the boundary at the outer edge, using 
  1143.  
  1144.             LINE (0,0) - (319,189), 1, B    
  1145.  
  1146. Then you need to check that any proposed x is between 0 and 319 and any y is 
  1147. between 0 and 189. 
  1148.  
  1149. 2. Use the program outlined last time (for interpreting the arrow keys) to 
  1150. create a new program that draws lines.  The pseudocode will be: 
  1151.  
  1152.             { draw a point in the middle of the screen}
  1153.  
  1154.             if {left arrow pressed} then { draw line segment to left}
  1155.  
  1156.             if {  up arrow pressed} then { draw line segment up     }
  1157.  
  1158.             ....
  1159.  
  1160. You can make the line segments some constant amount or a random amount.
  1161.  
  1162.  
  1163. 2. Use F3 & F4 to increase and decrease speed.  Remember to check for a 
  1164. speed of 0.  Don't let the speed go below 0, though.
  1165.  
  1166. 3. Use F5 to change the color of the lines being drawn
  1167.  
  1168. 4. Use F6 to draw a circle at the current location.
  1169.  
  1170. FOR SUPER-EXTRA CREDIT:
  1171. Last time we described a game in which you tried to control a moving cursor 
  1172. without hitting characters that were already on the screen.  This time we 
  1173. didn't include those rules in the game description.  Before reading further, 
  1174. try to think of reasons why this might not be as simple as it was with 
  1175. characters.  Can you think of methods by which you could get around these 
  1176. exercises?  (No need to write the actual programs.) 
  1177.  
  1178. Ready?
  1179.  
  1180. When you draw a line, how can you tell what pixels compose the line between 
  1181. the 2 points?  One of the strengths of the LINE command is also a drawback.  
  1182. We just tell it to draw a line from (x,y) to (x',y'), but we don't have to 
  1183. calculate the individual pixels that get drawn.  With characters, we know 
  1184. exactly which ones to look at.  For the line, we'd need to get out our trig 
  1185. manuals to calculate exactly which pixels were being covered. 
  1186.  
  1187. There are algorithms that describe how to tell if 2 lines intersect, or if a 
  1188. particular point is on a line, but even using these, we'd be stretching an 
  1189. interpreted language to try to do it all in realtime.  
  1190.  
  1191. Don't feel too bad if you didn't solve this exercise.  It's pretty difficult 
  1192. to find a solution that's both practical and fast.  The point rather is that 
  1193. Basic provides an extremely flexible method for investigating such involved 
  1194. and difficult exercises.  In several of my published games I've wrestled 
  1195. with these very problems.  My approach is to write short Basic programs 
  1196. first, examining the difficulties in detail.  When the problem's solved, I 
  1197. can then either compile it in PowerBasic or rewrite it in another language.   
  1198. So even if my final language is C or Pascal, Basic is often my first choice 
  1199. for quick & dirty graphics prototyping. 
  1200.  
  1201. ============================
  1202.  
  1203.  
  1204. The End of the Beginning
  1205. This completes the BASIC TRAINING TUTORIAL.  We've covered a large number of 
  1206. topics, and if you've done some of the exercises, projects and played with 
  1207. the example programs, you should have a solid grasp of the elements of Basic 
  1208. at this point.  What you do next depends on the types of programs you want 
  1209. to write.  If you're interested in studying more of what Basic can do, and 
  1210. what a compiler can add, the Advanced Tutorial will help.  When you 
  1211. register, you get it for free. 
  1212.  
  1213. ADVANCED BASIC.  Topics include: Animation techniques, Shape Shifting 
  1214. techniques, Error Handling, Chaining, Windows, Peek / poke, Bload / bsave, 
  1215. Plus, details on differences between interpreters and compilers. And 
  1216. complete source for all examples.  Advanced Basic is ONLY available to 
  1217. registered users.  
  1218.  
  1219. Registration costs only $20, and you will receive The Advanced Basic 
  1220. Tutorial as a bonus, along with more source code for all the examples in 
  1221. that tutorial.  
  1222.  
  1223. In addition, when you register you also get an evaluation copy of the 
  1224. LIBERTY Basic compiler for Windows.  This program lets you develop Basic 
  1225. programs in the Windows environment, without the need for the Windows 
  1226. Software Development Kit.
  1227.  
  1228. You might also want to order the Games Package option.  The Games package 
  1229. includes source code for 2 Cascoly programs that you can compile and modify 
  1230. for your personal use. 
  1231.  
  1232. ATC -- An air traffic controller game that's perfect for a few minutes or 
  1233. hours of fun.  Easy to learn, but difficult to master.  The game tracks best 
  1234. scores at each of 20 levels of difficulty.  Shows how to use real time 
  1235. interrupts and error detection.  
  1236.  
  1237. ECOMASTER -- The CGA version of Cascoly's ecology game.  A diverting ecology 
  1238. game in which you bid for and trade animals based on their abilities to 
  1239. thrive in different environments.   
  1240.  
  1241. To Register, return to DOS, and enter the command:
  1242.        REGISTER  
  1243. An order form will be printed for you.  Or send $20 + $4 shipping to:
  1244.         Cascoly Software    
  1245.         4528 36th Ave NE    
  1246.         Seattle WA 98105    
  1247.  
  1248.